package com.gitee.l0km.beanfilter.core;

import static com.gitee.l0km.beanfilter.core.BaseFieldFilter.EMPTY_STRING_ARRAY;

import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.TypeUtils;
import com.gitee.l0km.aocache.annotations.AoWeakCacheable;
import com.gitee.l0km.beanfilter.core.utils.CaseSupport;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;

/**
 * 字段值过滤简单实现
 * @author guyadong
 */
public class SimpleValueFilter implements IValueFilter {
	private final ConcurrentHashMap<String,Optional<Object>> constValues = new ConcurrentHashMap<>();
	private final SimpleFieldFilter fieldFilter;
	private final boolean autoCase;
	public SimpleValueFilter(Class<?> beanClass, boolean autoCase,String fieldName,String stringValue,Class<?> constantType) {
		this(beanClass,autoCase);
		withConstant(fieldName, stringValue,constantType);
	}

	public SimpleValueFilter(Class<?> beanClass, boolean autoCase) {
		this(beanClass, 
				autoCase,
				null);
	}
	public SimpleValueFilter(Class<?> beanClass, boolean autoCase,Map<String,?> constantValues) {
		this(beanClass, 
				autoCase,
				constantValues, 
				null,null, true);
	}

	public SimpleValueFilter(Class<?> beanClass, boolean autoCase,Map<String,?> constantValues,Class<?>[] activeOnClasses,String[] activeOnClassNames, boolean and) {
		this.fieldFilter = new SimpleFieldFilter(beanClass,autoCase,
				true,
				EMPTY_STRING_ARRAY,
				null == constantValues ? EMPTY_STRING_ARRAY : constantValues.keySet().toArray(new String[0]),activeOnClasses, activeOnClassNames,
				and,
				EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY);
		this.autoCase = autoCase;
		withConstants(constantValues);
	}
	/**
	 * {@code com.gitee.l0km.beanfilter.core.annotations.ConstantValueFilter} 注解定义的 构造方法
	 * @param beanClass Java Bean类型
	 * @param autoCase 是否将snake-case和camel-case格式的字段字视为同一字段，如firstName和first_name,为{@code true}时视为同一个名字。
	 * @param fieldName 要过滤字段名
	 * @param consantValue 返回的字段值
	 * @param constantType 要求的返回字段值类型
	 * @param activeOnClasses 过滤器激活器类型列表，必须为{@link Activation}接口实现
	 * @param activeOnClassNames  过滤器激活器类名列表，必须为{@link Activation}接口实现类名
	 * @param and 指定多个过滤器激活器时，激活判断模式，为{@code true}为AND模式，所有激活器条件都匹配才能激活过滤器，否则为OR模式，任意一激活器条件都匹配就可以激活过滤器
	 */
	public SimpleValueFilter(Class<?> beanClass, boolean autoCase,String fieldName,String consantValue,Class<?> constantType,Class<?>[] activeOnClasses, String[] activeOnClassNames, boolean and) {
		this(beanClass,autoCase,ImmutableMap.of(fieldName,consantValue),activeOnClasses,activeOnClassNames, and);
	}
	public SimpleValueFilter withConstants(Map<String,?> constValues) {
		if(null != constValues) {
			this.constValues.clear();
			for(Entry<String, ?> entry:constValues.entrySet()) {
				withConstant(entry.getKey(),entry.getValue());
			}
		}
		return this;
	}
	public SimpleValueFilter withConstant(String name,Object value) {
		if(null != name) {
			if(autoCase) {
				name = CaseSupport.toCamelcaseIfSnake(name);
			}
			this.constValues.put(name,Optional.fromNullable(value));
		}
		return this;
	}
	public SimpleValueFilter withConstant(String name,Object value,Class<?> constantType) {
		if(null!=value && constantType !=null&& constantType!=Object.class) {
			value = TypeUtils.cast(value, constantType, ParserConfig.getGlobalInstance());
		}
		return withConstant(name,value);
	}
	
	public Class<?> getBeanClass() {
		return fieldFilter.getBeanClass();
	}

	public Map<String, Optional<Object>> getConstValues() {
		return constValues;
	}

	@AoWeakCacheable(maximumSize = 200, expireAfterAccess = 20, expireAfterAccessTimeUnit = TimeUnit.SECONDS)
	protected Object doProcess(Class<?> clazz,String name, Object value) {
		if(autoCase) {
			name = CaseSupport.toCamelcaseIfSnake(name);
		}
		if(constValues.containsKey(name)) {
			return constValues.get(name).orNull();
		}
		return value;
	}
	@Override
	public Object process(Class<?> clazz,String name, Object value) {
		if(fieldFilter.isActive(clazz) && null != clazz && null != name && fieldFilter.permit(clazz, name)) {
			return doProcess(clazz,name,value);
		}
		return value;
	}

	@Override
	public int hashCode() {
		return Objects.hash(constValues, fieldFilter);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		SimpleValueFilter other = (SimpleValueFilter) obj;
		return Objects.equals(constValues, other.constValues) && Objects.equals(fieldFilter, other.fieldFilter);
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("SimpleValueFilter [constValues=").append(constValues).append(", fieldFilter=")
				.append(fieldFilter).append("]");
		return builder.toString();
	}
}
